﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_BITFIELD_TYPE_H
#define _UXS_BITFIELD_TYPE_H

#pragma once

#include "Types.h"
#include "../CompileTime/TTypeInfo.h"

namespace UX_STL
{
namespace UXTypes
{

	//
	// Bitfield
	//
	
	template <uint B>
	struct TBitfield
	{
	// types
	public:
		struct TBitRef;
		typedef TBitfield< B >								Self;
		typedef typename NearInt::UnsignedBits< B >::type	T;
		typedef T											value_t;

	// variables
	private:
		T	_uBits	: B;

		//  ||||||||||||
		// B-1         0

	// methods
	public:
		explicit
		TBitfield(const T bits = T()): _uBits(bits)	{}
		
		bool	Get(uint i) const					{ ASSUME(i<B);  return !!( _uBits & (1 << i) ); }
		Self &	Set(uint i)							{ ASSUME(i<B);  _uBits |= 1 << i;  return *this; }
		Self &	Reset(uint i)						{ ASSUME(i<B);  _uBits ^= 1 << i;  return *this; }
		Self &	Set(uint i, bool bit)				{ ASSUME(i<B); (_uBits &= ~(1<<i)) |= bit<<i;  return *this; }

		Self &	And(uint i, bool bit)				{ ASSUME(i<B);  _uBits &= bit << i;  return *this; }
		Self &	Or(uint i, bool bit)				{ ASSUME(i<B);  _uBits |= bit << i;  return *this; }
		Self &	Xor(uint i, bool bit)				{ ASSUME(i<B);  _uBits ^= bit << i;  return *this; }

		Self &	SetAll(bool bit)					{ bit ? _uBits = T(-1) : _uBits = 0;  return *this; }

		bool	IsZero() const						{ return _uBits == 0; }
		bool	IsNotZero() const					{ return _uBits != 0; }

		operator T () const							{ return _uBits; }

		static uint Count ()						{ return B; }

		Self	operator ~  ()	const				{ return Self( ~_uBits ); }

		Self &	operator =  (const T right)			{ _uBits =   right;  return *this; }

		Self &	operator |= (const T right)			{ _uBits |=  right;  return *this; }
		Self &	operator &= (const T right)			{ _uBits &=  right;  return *this; }
		Self &	operator ^= (const T right)			{ _uBits ^=  right;  return *this; }
		
		Self &	operator >>= (const T right)		{ _uBits >>= right;  return *this; }
		Self &	operator <<= (const T right)		{ _uBits <<= right;  return *this; }

		Self	operator |  (const T right) const	{ return Self( _uBits | right ); }
		Self	operator &  (const T right) const	{ return Self( _uBits & right ); }
		Self	operator ^  (const T right) const	{ return Self( _uBits ^ right ); }
		
		Self	operator >> (const T right) const	{ return Self( _uBits >> right ); }
		Self	operator << (const T right) const	{ return Self( _uBits << right ); }

		bool 	operator [] (uint i) const			{ return Get( i ); }
		TBitRef	operator [] (uint i)				{ ASSUME(i<B);  return TBitRef( *this, i ); }
		

		void SetInterval (uint first, uint last)
		{
			ASSUME( first <= last and last < B );

			for (uint i = first; i <= last; ++i) {
				_uBits |= 1 << i;
			}
		}

		void ResetInterval (uint first, uint last)
		{
			ASSUME( first <= last and last < B );

			for (uint i = first; i <= last; ++i) {
				_uBits ^= 1 << i;
			}
		}

		bool HasInterval (uint first, uint last) const
		{
			ASSUME( first <= last and last < B );

			bool	result = true;

			for (uint i = first; i <= last and result; ++i) {
				result = Get( i );
			}

			return result;
		}

		bool HasAnyInterval (uint length, OUT uint &firstBit) const
		{
			ASSUME( length > 0 and length < B );

			uint	counter = 0;

			for (uint i = 0; i < B; ++i)
			{
				bool	bit = Get( i );

				if ( bit )
				{
					counter++;

					if ( counter == length )
					{
						firstBit = i - length;
						return true;
					}
				}
				else
				{
					counter = 0;
				}
			}
			return false;
		}


	public:
		struct TBitRef
		{
		private:
			TBitfield<B> &	_sBitfield;
			uint			_uIndex;

			void _Set()				{ _sBitfield.Set( _uIndex ); }
			void _Reset()			{ _sBitfield.Reset( _uIndex ); }
			void _Set(bool bit)		{ _sBitfield.Set( _uIndex, bit ); }
			void _And(bool bit)		{ _sBitfield.And( _uIndex, bit ); }
			void _Or(bool bit)		{ _sBitfield.Or( _uIndex, bit ); }
			void _Xor(bool bit)		{ _sBitfield.Xor( _uIndex, bit ); }
			bool _Get() const		{ return _sBitfield.Get( _uIndex ); }

		public:
			TBitRef (TBitfield<B> &bitfield, uint index):
				_sBitfield( bitfield ), _uIndex(index)
			{}

			TBitRef & operator = (const TBitRef &bit)
			{
				_Set( bit._Get() );
				return *this;
			}

			template <typename C>
			TBitRef & operator = (const C &right)
			{
				_Set( (bool)right );
				return *this;
			}

			operator bool () const
			{
				return _Get();
			}

			template <typename C>
			operator C () const
			{
				return C( _Get() );
			}

			template <typename C>
			TBitRef &	operator |= (const C right)
			{
				_Or( (bool)right );
				return *this;
			}

			template <typename C>
			TBitRef &	operator &= (const C right)
			{
				_And( (bool)right );
				return *this;
			}

			template <typename C>
			TBitRef &	operator ^= (const C right)
			{
				_Xor( (bool)right );
				return *this;
			}
		};


		STATIC_ASSERT( (sizeof(T)<<3) >= B, "incorrect template args" );
	};


	typedef TBitfield< 8 >		bitfield8_t;
	typedef TBitfield< 16 >		bitfield16_t;
	typedef TBitfield< 32 >		bitfield32_t;
	typedef TBitfield< 64 >		bitfield64_t;

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_BITFIELD_TYPE_H